package cn.skycity.auth.authentication;

import cn.skycity.auth.utils.OAuth2EndpointUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.lang.Nullable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2AuthorizationCodeAuthenticationConverter;
import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @Decription 使用用户名和密码进行登录
 * 参考： {@link OAuth2AuthorizationCodeAuthenticationConverter}
 * @Author YingBo.Dai
 * @Date 2022/10/24 21:42
 * @Version 1.0
 */
public final class OAuth2ResourcePasswordAuthenticationConverter implements AuthenticationConverter {

    @Nullable
    @Override
    public Authentication convert(HttpServletRequest request) {
        String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
        if (!AuthorizationGrantType.PASSWORD.getValue().equals(grantType)) {
            return null;
        }else{
            Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();

            MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getParameters(request);
            String scope = OAuth2EndpointUtils.checkOptionalParameter(parameters, "scope");
            Set<String> requestedScopes = null;
            if (StringUtils.hasText(scope)) {
                requestedScopes = new HashSet<>(Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
            }
            String username = OAuth2EndpointUtils.checkRequiredParameter(parameters,OAuth2ParameterNames.USERNAME);
            String password = OAuth2EndpointUtils.checkRequiredParameter(parameters,OAuth2ParameterNames.PASSWORD);
            Map<String,Object> additionalParameters = new HashMap<>();
            parameters.forEach((key, value) -> {
                if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) &&
                        !key.equals(OAuth2ParameterNames.USERNAME) &&
                        !key.equals(OAuth2ParameterNames.PASSWORD) &&
                        !key.equals(OAuth2ParameterNames.SCOPE)) {
                    additionalParameters.put(key, value.get(0));
                }
            });
            return new OAuth2ResourcePasswordAuthenticationToken(username,password,clientPrincipal, requestedScopes, additionalParameters);
        }
    }
}
